//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Text.RegularExpressions;
using OpenLS.Spreadsheet.Extensibility;

namespace OpenLS.Spreadsheet.StandardAddIn
{
    internal class Criteria
    {
        private readonly object _anchorValue;
        private readonly object _originalString;

        private readonly Regex _regex;
        private readonly IWorkbook _workbook;
        private readonly CriteriaOperator op;

        public Criteria(IWorkbook workbook, object obj)
        {
            _workbook = workbook;
            _originalString = obj;
            if (obj is int)
                obj = (double) (int) obj;
            if (obj is double)
            {
                _anchorValue = obj;
                op = CriteriaOperator.Equal;
                return;
            }
            var s = (string) obj;
            if (s.Length == 0)
                return;
            switch (s[0])
            {
                case '>':
                    if (s[1] == '=')
                    {
                        op = CriteriaOperator.GreaterThanOrEqual;
                        s = s.Substring(2);
                        break;
                    }
                    op = CriteriaOperator.GreaterThan;
                    s = s.Substring(1);
                    break;
                case '<':
                    if (s[1] == '=')
                    {
                        op = CriteriaOperator.LessThanOrEqual;
                        s = s.Substring(2);
                        break;
                    }
                    if (s[1] == '>')
                    {
                        op = CriteriaOperator.NotEqual;
                        s = s.Substring(2);
                        break;
                    }
                    op = CriteriaOperator.LessThan;
                    s = s.Substring(1);
                    break;
                case '=':
                    op = CriteriaOperator.Equal;
                    s = s.Substring(1);
                    break;
                case '~':
                    throw new NotImplementedException();
            }
            double dbl;
            int percent = 1;
            if (s.Trim().EndsWith("%"))
            {
                s = s.Trim().Substring(0, s.Trim().Length - 1)
                    ;
                percent = 100;
            }
            if (double.TryParse(s, out dbl))
            {
                _anchorValue = dbl/percent;
            }
            else
            {
                DateTime dt;
                if (DateTime.TryParse(s, out dt))
                {
                    _anchorValue = workbook.DateTimeToDouble(dt);
                }
                else
                    _anchorValue = s;
                string regexPattern;
                if (s == "*") regexPattern = ".{1,}";
                else
                    regexPattern =
                        s.Replace(".", "\\.").Replace("*", ".*").Replace("?", ".").Replace("(", "\\(").Replace(")",
                                                                                                               "\\)").
                            Replace("]", "\\]").Replace("[", "\\[");
                regexPattern = "^" + regexPattern + @"\z";
                _regex = new Regex(regexPattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);
            }
        }

        public bool Matches(object value)
        {
            if (value is ICell)
                value = ((ICell) value).Value;
            if (_anchorValue == null)
                return value == null;
            if (_anchorValue is double)
            {
                var anchorDouble = (double) _anchorValue;
                double actualValue;
                if (value is double)
                    actualValue = (double) value;
                else if (value is int)
                    actualValue = (int) value;
                else if (value is DateTime)
                    actualValue = _workbook.DateTimeToDouble((DateTime) value);
                else if (value is bool)
                {
                    if ((bool) value)
                        actualValue = 1;
                    else
                        actualValue = 0;
                }
                else if (value is string)
                {
                    return (_originalString == value);
                }
                else
                    return false;
                switch (op)
                {
                    case CriteriaOperator.Equal:
                        return actualValue == anchorDouble;
                    case CriteriaOperator.GreaterThanOrEqual:
                        return actualValue >= anchorDouble;
                    case CriteriaOperator.GreaterThan:
                        return actualValue > anchorDouble;
                    case CriteriaOperator.LessThan:
                        return actualValue < anchorDouble;
                    case CriteriaOperator.NotEqual:
                        return actualValue != anchorDouble;
                    case CriteriaOperator.LessThanOrEqual:
                        return actualValue <= anchorDouble;

                    default:
                        throw new NotSupportedException();
                }
            }
            else if (_anchorValue is string)
            {
                var AnchorString = (string) _anchorValue;
                string actualString = "";
                if (value != null)
                    actualString = value.ToString();
                switch (op)
                {
                    case CriteriaOperator.Equal:
                        bool result = _regex.IsMatch(actualString);
                        Debug.WriteLine("Match " + _regex + " " + actualString + " " + result);
                        return result;
                    case CriteriaOperator.NotEqual:
                        bool result2 = !_regex.IsMatch(actualString);
                        Debug.WriteLine("(not equal) Match " + _regex + " " + actualString + " " + result2);
                        return result2;

                    default:
                        throw new NotImplementedException();
                }
            }
            Contract.Assert(_anchorValue != null);
            throw new NotImplementedException();
        }
    }
}